
//----------------------------------------

#include "iicps.h"
#include "uartps.h"
#include "xiicps.h"
#define			BUFFER_SIZE		64

char			char_buffer_rx[BUFFER_SIZE];
char			char_buffer_tx[BUFFER_SIZE];
unsigned int	data_buffer[BUFFER_SIZE]={0};
u8				send_buffer[BUFFER_SIZE];
u8				recv_buffer[BUFFER_SIZE];
u8				cmd_byte;
u8				num_byte;
u8				rom_mode;
u16				rom_addr;

void cmd_rom_dac(void)
{
		int Status,val;

start:	for(int i=0;i<BUFFER_SIZE;i++){//clean buffer
			char_buffer_rx[i]='\n';
			char_buffer_tx[i]='\n';
			send_buffer[i]='\n';
			recv_buffer[i]='\n';
			data_buffer[i]= 0;
		}

		xil_printf("\r\n- - - - - - - - - - - - - - - - - -\r\n");
		xil_printf("Example: DA(cmd) 03(len) 10 0000(hex)---min\r\n");
		xil_printf("Example: DA(cmd) 03(len) 10 D333(hex)---max\r\n");
		xil_printf("Example: EE(cmd) 0000(addr16) 00(wr) 02(len)AABB(hex)\r\n");
 	 	xil_printf("Example: EE(cmd) 0000(addr16) 01(wo) 01(len)AA(hex)\r\n");
 	 	xil_printf("Example: EE(cmd) 0000(addr16) 02(ro) 04(len)\r\n");
 	 	xil_printf("Enter 'q' to quit.\r\n");
		xil_printf("Uart waiting for input...\r\n");
		uart_recv_string(char_buffer_rx);

		if(char_buffer_rx[0]=='q'){
			goto quit;
		}

		val=char_to_hex(char_buffer_rx,data_buffer,BUFFER_SIZE,2);
		if(val) goto exit;

		//head
		cmd_byte = (u8)data_buffer[0];

		//dac slave
		if(cmd_byte==0xDA){//exp: 0xDA(cmd) 03(len) 10_11_22(data)  (V_out=V_ref*D/65536)
			num_byte = (u8)data_buffer[1];
			for(int i=0;i<num_byte;i++)
			send_buffer[i]=(u8)data_buffer[i+2];

			if(send_buffer[1]>0xD3){
				xil_printf("valtage should less then 3.3v\r\n");
				goto start;
			}

			Status = IicPsMasterInit(IIC_BUS_3,IIC_SLAVE_ADDR);
			if (Status != XST_SUCCESS) {
				xil_printf("iic initial error!\r\n");
				goto start;
			}

			Status = IicPsMasterSend((u8*)send_buffer,num_byte);
			if (Status != XST_SUCCESS) {
				xil_printf("iic write failed!\r\n");
				goto start;
			}

			Status = IicPsMasterRecv((u8*)recv_buffer,num_byte);
			if (Status != XST_SUCCESS) {
				xil_printf("iic read failed!\r\n");
				goto start;
			}

		}
		//eeprom slave
		else if(cmd_byte==0xEE){//exp: 0xEE(cmd)00(addr)00(w\r)08(len)20190805_AABBCCDD(hex)

#if(EEPROM_ADDR_WIDTH==8)
			rom_addr = (u16)data_buffer[1];
			rom_mode = (u8)data_buffer[2];
			num_byte = (u8)data_buffer[3];
			for(int i=0;i<num_byte;i++)
			send_buffer[i]=(u8)data_buffer[i+4];
#else
			rom_addr = (u16)(data_buffer[1]<<8)|(data_buffer[2]<<0);
			rom_mode = (u8)data_buffer[3];
			num_byte = (u8)data_buffer[4];
			for(int i=0;i<num_byte;i++)
			send_buffer[i]=(u8)data_buffer[i+5];
#endif

			Status = IicPsMasterInit(IIC_MUX_SWITCH,IIC_EEPROM_ADDR);
			if (Status != XST_SUCCESS) {
				xil_printf("iic initial error!\r\n");
				goto start;
			}

			if(rom_mode==WRITE_THEN_READ||rom_mode==WRITE_ONLY){
				Status = EepromWriteDataAddress(send_buffer,num_byte,rom_addr);
				if (Status != XST_SUCCESS) {
					xil_printf("iic write failed!\r\n");
					goto start;
				}
				if(rom_mode) goto start;
			}

			if(rom_mode==WRITE_THEN_READ||rom_mode==READ_ONLY){
				Status = EepromReadDataAddress(recv_buffer,num_byte,rom_addr);
				if (Status != XST_SUCCESS) {
					xil_printf("iic read failed!\r\n");
					goto start;
				}
			}

		}
		//format wrong
		else{
exit:		xil_printf("Error data format !\r\n");
		 	goto start;
		}

		val=hex_to_char(char_buffer_tx,recv_buffer,num_byte,2);
		if(val) goto quit;

		xil_printf("%02x iic data echo= 0x",cmd_byte);
		uart_send_string(char_buffer_tx);
		goto start;
quit:	xil_printf("Quit iic.\r\n");

}


int iic_rom_dac(void)
{
	int Status;
	u8 vol[3],tmp[3];
	//u16 StartAddr = EEPROM_START_ADDRESS;

	/*only one iic switch bus can be used at the same time.*/
	//read eeprom
	Status = IicPsMasterInit(IIC_MUX_SWITCH,IIC_EEPROM_ADDR);
	if (Status != XST_SUCCESS) {
		xil_printf("rom initial error!\r\n");
	}

	Status = EepromReadDataAddress((u8*)vol,0x02,0x0000);
	if (Status != XST_SUCCESS) {
		xil_printf("rom read failed!\r\n");
	}

	if(vol[0]>0xD3){
		xil_printf("valtage should less then 3.3v\r\n");
		return 1;
	}

	//write dac
	Status = IicPsMasterInit(IIC_BUS_3,IIC_SLAVE_ADDR);
	if (Status != XST_SUCCESS) {
		xil_printf("dac initial error!\r\n");
	}

	vol[2]=vol[1];
	vol[1]=vol[0];
	vol[0]=0x10;
	Status = IicPsMasterSend((u8*)vol,0x3);
	if (Status != XST_SUCCESS) {
		xil_printf("dac write failed!\r\n");
	}

	Status = IicPsMasterRecv((u8*)tmp,0x3);
	if (Status != XST_SUCCESS) {
		xil_printf("dac read failed!\r\n");
	}else
	{
		xil_printf("dac read back : 0x%02x%02x\r\n",tmp[0],tmp[1]);
	}

	return 0;
}


int IicPsMasterInit(u8 mux_bus, u16 iic_addr)
{
	int Status;

	Status = IicPsConfig(IIC_DEVICE_ID,IIC_INT_VEC_ID);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
/*
	Status = IicPsFindDevice(IIC_MUX_ADDRESS);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	Status = MuxInit(mux_bus);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
*/
	Status = IicPsFindDevice(iic_addr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	return XST_SUCCESS;
}



/*****************************************************************************/
/**
*
* This function checks the availability of a slave using slave monitor mode.
*
* @param	DeviceId is the Device ID of the IicPs Device and is the
*		XPAR_<IICPS_instance>_DEVICE_ID value from xparameters.h
*
* @return	XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note 	None.
*
*******************************************************************************/
int IicPsFindDevice(u16 Address)
{
	u32 Index;
	XIicPs *IicPtr;

	SlaveResponse = FALSE;

	IicPtr = &I2C;
	XIicPs_DisableAllInterrupts(IicPtr->Config.BaseAddress);
	XIicPs_EnableSlaveMonitor(&I2C, Address);
	//===============
	TotalErrorCount = 0;

	Index = 0;

	/*
	 * Wait for the Slave Monitor Interrupt, the interrupt processing
	 * works in the background, this function may get locked up in this
	 * loop if the interrupts are not working correctly or the slave
	 * never responds.
	 */
	while ((!SlaveResponse) && (Index < SLV_MON_LOOP_COUNT)) {
		Index++;

		/*
		 * Ignore any errors. The hardware generates NACK interrupts
		 * if the slave is not present.
		 */
		if (0 != TotalErrorCount) {
			xil_printf("Test error unexpected NACK\n");
			return XST_FAILURE;
		}
	}

	if (Index >= SLV_MON_LOOP_COUNT) {
		return XST_FAILURE;

	}

	XIicPs_DisableSlaveMonitor(&I2C);
	return XST_SUCCESS;
}



int IicPsConfig(u16 DeviceId, u32 Int_Id)
{
	int Status;
	XIicPs_Config *Config;

	/*
	 * Initialize the IIC driver so that it's ready to use
	 * Look up the configuration in the config table,
	 * then initialize it.
	 */
	Config = XIicPs_LookupConfig(DeviceId);
	if (NULL == Config) {
		return XST_FAILURE;
	}

	Status = XIicPs_CfgInitialize(&I2C, Config, Config->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Perform a self-test to ensure that the hardware was built correctly.
	 */
	Status = XIicPs_SelfTest(&I2C);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Connect the IIC to the interrupt subsystem such that interrupts can
	 * occur. This function is application specific.
	 */
	Status = SetupInterruptSystem(&I2C,Int_Id);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Setup the handlers for the IIC that will be called from the
	 * interrupt context when data has been sent and received, specify a
	 * pointer to the IIC driver instance as the callback reference so
	 * the handlers are able to access the instance data.
	 */
	XIicPs_SetStatusHandler(&I2C, (void *) &I2C, Handler);
	/*
	 * Set the IIC serial clock rate.
	 */
	Status = XIicPs_SetSClk(&I2C, IIC_SCLK_RATE);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}


	return XST_SUCCESS;
}


int IicPsMasterSend(u8 *SendBuffer,s32 ByteCount)
{
	while (XIicPs_BusIsBusy(&I2C));
	SendComplete = FALSE;
	XIicPs_MasterSend(&I2C, SendBuffer, ByteCount, IIC_SLAVE_ADDR);
	
	while (!SendComplete) {
		if (0 != TotalErrorCount) {
			return XST_FAILURE;
		}
	}
	
	return XST_SUCCESS;
}

int IicPsMasterRecv(u8 *RecvBuffer,s32 ByteCount)
{
	while (XIicPs_BusIsBusy(&I2C));
	RecvComplete = FALSE;
	XIicPs_MasterRecv(&I2C, RecvBuffer, ByteCount, IIC_SLAVE_ADDR);
	
	while (!RecvComplete) {
		if (0 != TotalErrorCount) {
			return XST_FAILURE;
		}
	}
	
	return XST_SUCCESS;
}


int MuxInit(u8 channel)
{
	u8 WriteBuffer = channel;
	u8 MuxIicAddr  = IIC_MUX_ADDRESS;
	u8 ReadBuffer  = 0;
	TotalErrorCount = 0;
	/*
	 * Send the Data.
	 */
	SendComplete = FALSE;
	XIicPs_MasterSend(&I2C,&WriteBuffer,1,MuxIicAddr);
	while (SendComplete == FALSE) {
		if (0 != TotalErrorCount) {
			return XST_FAILURE;
		}
	}

	/*
	 * Wait until bus is idle to start another transfer.
	 */
	while (XIicPs_BusIsBusy(&I2C));

	/*
	 * Receive the Data.
	 */
	RecvComplete = FALSE;
	XIicPs_MasterRecv(&I2C,&ReadBuffer,1,MuxIicAddr);
	while (RecvComplete == FALSE) {
		if (0 != TotalErrorCount) {
			return XST_FAILURE;
		}
	}

	/*
	 * Wait until bus is idle to start another transfer.
	 */
	while (XIicPs_BusIsBusy(&I2C));

	return XST_SUCCESS;
}


int SetupInterruptSystem(XIicPs *IicPsPtr, u32 Int_Id)
{
	int Status;
	XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */

	Xil_ExceptionInit();

	/*
	 * Initialize the interrupt controller driver so that it is ready to
	 * use.
	 */
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfig) {
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(&InterruptController, IntcConfig,
					IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	/*
	 * Connect the interrupt controller interrupt handler to the hardware
	 * interrupt handling logic in the processor.
	 */
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
				(Xil_ExceptionHandler)XScuGic_InterruptHandler,
				&InterruptController);

	/*
	 * Connect the device driver handler that will be called when an
	 * interrupt for the device occurs, the handler defined above performs
	 * the specific interrupt processing for the device.
	 */
	Status = XScuGic_Connect(&InterruptController, Int_Id,
			(Xil_InterruptHandler)XIicPs_MasterInterruptHandler,
			(void *)IicPsPtr);
	if (Status != XST_SUCCESS) {
		return Status;
	}

	/*
	 * Enable the interrupt for the Iic device.
	 */
	XScuGic_Enable(&InterruptController, Int_Id);

	/*
	 * Enable interrupts in the Processor.
	 */
	Xil_ExceptionEnable();

	return XST_SUCCESS;
}


void Handler(void *CallBackRef, u32 Event)
{
	/*
	 * All of the data transfer has been finished.
	 */
	if (0 != (Event & XIICPS_EVENT_COMPLETE_RECV)){
		RecvComplete = TRUE;
	} else if (0 != (Event & XIICPS_EVENT_COMPLETE_SEND)) {
		SendComplete = TRUE;
	} else if (0 != (Event & XIICPS_EVENT_SLAVE_RDY)) {
		SlaveResponse = TRUE;
	} else if (0 != (Event & XIICPS_EVENT_ERROR)){
		TotalErrorCount++;
	}
}

/*****************************************************************************/
/**
* This function writes a buffer of data to the IIC serial EEPROM.
*
* @param	ByteCount contains the number of bytes in the buffer to be
*		written.
*
* @return	XST_SUCCESS if successful else XST_FAILURE.
*
* @note		The Byte count should not exceed the page size of the EEPROM as
*		noted by the constant PAGE_SIZE.
*
******************************************************************************/
int EepromWriteData(u8 *WriteBuffer, u16 ByteCount)
{

	SendComplete = FALSE;

	XIicPs_MasterSend(&I2C, WriteBuffer, ByteCount, IIC_EEPROM_ADDR);

	while (SendComplete == FALSE) {
		if (0 != TotalErrorCount) {
			return XST_FAILURE;
		}
	}
	/*
	 * Wait until bus is idle to start another transfer.
	 */
	while (XIicPs_BusIsBusy(&I2C));
	/*
	 * Wait for a bit of time to allow the programming to complete
	 */
	usleep(200*1000);

	return XST_SUCCESS;
}


int EepromWriteDataAddress(u8 *DataBuffer, u16 ByteCount, u16 StartAddr)
{
	int Status;
	u16 AddrLen = ADDR_LEN;
	u16 DataLen = ByteCount;
	u8  WriteBuffer[AddrLen+DataLen];

	for(int i=0;i<DataLen;i++)
	WriteBuffer[i+AddrLen]=DataBuffer[i];

#if(EEPROM_ADDR_WIDTH==8)
	WriteBuffer[0]=(u8)(StartAddr);//L
#else
	WriteBuffer[0]=(u8)(StartAddr);//L
	WriteBuffer[1]=(u8)(StartAddr>>8);//H
#endif
	Status = EepromWriteData((u8*)WriteBuffer,AddrLen+DataLen);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}


/*****************************************************************************/
/**
* This function reads data from the IIC serial EEPROM into a specified buffer.
*
* @param	BufferPtr contains the address of the data buffer to be filled.
* @param	ByteCount contains the number of bytes in the buffer to be read.
*
* @return	XST_SUCCESS if successful else XST_FAILURE.
*
* @note		None.
*
******************************************************************************/
int EepromReadDataAddress(u8 *DataBuffer, u16 ByteCount, u16 StartAddr)
{
	int  Status;
	u16  AddressLen = ADDR_LEN;
	char AddrBuffer[AddressLen];

#if(EEPROM_ADDR_WIDTH==8)
	AddrBuffer[0] = (u8) (StartAddr);
#else
	AddrBuffer[0] = (u8) (StartAddr >> 8);
	AddrBuffer[1] = (u8) (StartAddr);
#endif
	Status = EepromWriteData((u8*)AddrBuffer,AddressLen);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	RecvComplete = FALSE;

	XIicPs_MasterRecv(&I2C, DataBuffer, ByteCount, IIC_EEPROM_ADDR);

	while (RecvComplete == FALSE) {
		if (0 != TotalErrorCount) {
			return XST_FAILURE;
		}
	}
	/*
	 * Wait until bus is idle to start another transfer.
	 */
	while (XIicPs_BusIsBusy(&I2C));

	return XST_SUCCESS;
}




